# -*- coding: utf-8 -*-
"""
参数优化设置对话框
"""
from PySide6.QtWidgets import (QVBoxLayout, QHBoxLayout, QGridLayout, QLabel, 
                               QSpinBox, QScrollArea, QWidget, QFrame)
from PySide6.QtCore import Signal, Qt
from ui.components.base.base_dialog import TgBaseDialog
from ui.components.buttons.button import TgButton
from ui.components.inputs.combo_box import TgComboBox
from ui.components.inputs.line_edit import TgLineEdit
from ui.components.layouts.vbox_layout import TgVBoxLayout
from ui.components.layouts.hbox_layout import TgHBoxLayout
from ui.components.composite.form_layout import TgFormLayout
from services.backtesting_service import OptimizationSetting
from loguru import logger
import os


class OptimizationSettingDialog(TgBaseDialog):
    """参数优化设置对话框"""
    
    # 优化目标映射
    TARGET_DISPLAY_MAP = {
        "总收益率": "total_return",
        "年化收益率": "annual_return", 
        "夏普比率": "sharpe_ratio",
        "EWM夏普比率": "ewm_sharpe",
        "收益回撤比": "return_drawdown_ratio",
        "日均盈亏": "daily_net_pnl",
        "最大回撤": "max_drawdown",
        "胜率": "win_rate"
    }
    
    def __init__(self, strategy_name: str, strategy_params: dict, parent=None):
        self.strategy_name = strategy_name
        self.strategy_params = strategy_params or {}
        self.parameter_editors = {}
        self.optimization_setting = None
        self.use_ga = False
        super().__init__(parent)
        self.setWindowTitle(f"参数优化设置 - {strategy_name}")
        self.resize(800, 600)
    
    def setup_ui(self):
        """设置UI"""
        main_layout = TgVBoxLayout(self)
        
        # 优化目标选择
        target_form = TgFormLayout()
        self.target_combo = TgComboBox()
        self.target_combo.addItems(list(self.TARGET_DISPLAY_MAP.keys()))
        target_form.add_row("优化目标:", self.target_combo)
        
        # 进程数设置
        cpu_count = os.cpu_count() or 1
        default_workers = max(1, cpu_count - 1)
        
        self.worker_spin = QSpinBox()
        self.worker_spin.setRange(1, cpu_count)
        self.worker_spin.setValue(default_workers)
        self.worker_spin.setToolTip(f"当前系统可用CPU核数: {cpu_count}")
        target_form.add_row(f"进程数(最大{cpu_count}):", self.worker_spin)
        
        main_layout.addWidget(target_form)
        
        # 参数设置区域
        param_frame = QFrame()
        param_frame.setFrameStyle(QFrame.StyledPanel)
        param_layout = QVBoxLayout(param_frame)
        
        # 参数标题
        param_title = QLabel("参数范围设置")
        param_title.setStyleSheet("font-weight: bold; font-size: 14px; padding: 5px;")
        param_layout.addWidget(param_title)
        
        # 参数表格头部
        header_layout = QHBoxLayout()
        header_layout.addWidget(QLabel("参数名"))
        header_layout.addWidget(QLabel("开始值"))
        header_layout.addWidget(QLabel("步进值"))
        header_layout.addWidget(QLabel("结束值"))
        header_layout.addWidget(QLabel("启用"))
        param_layout.addLayout(header_layout)
        
        # 滚动区域用于参数设置
        scroll_area = QScrollArea()
        scroll_widget = QWidget()
        self.param_grid_layout = QGridLayout(scroll_widget)
        
        # 为每个策略参数创建编辑器
        row = 0
        for param_name, default_value in self.strategy_params.items():
            self._create_parameter_editor(row, param_name, default_value)
            row += 1
        
        scroll_area.setWidget(scroll_widget)
        scroll_area.setWidgetResizable(True)
        param_layout.addWidget(scroll_area)
        
        main_layout.addWidget(param_frame)
        
        # 按钮区域
        button_layout = TgHBoxLayout()
        button_layout.addStretch()
        
        self.parallel_button = TgButton("多进程优化", theme="primary")
        # self.ga_button = TgButton("遗传算法优化", theme="secondary") 
        self.cancel_button = TgButton("取消", theme="secondary")
        
        self.parallel_button.clicked.connect(self._on_parallel_optimization)
        # self.ga_button.clicked.connect(self._on_ga_optimization)
        self.cancel_button.clicked.connect(self.reject)
        
        button_layout.addWidget(self.parallel_button)
        # button_layout.addWidget(self.ga_button)
        button_layout.addWidget(self.cancel_button)
        
        main_layout.addLayout(button_layout)
    
    def _create_parameter_editor(self, row: int, param_name: str, default_value):
        """创建参数编辑器"""
        # 参数名标签
        name_label = QLabel(param_name)
        self.param_grid_layout.addWidget(name_label, row, 0)
        
        # 开始值、步进值、结束值输入框
        start_edit = TgLineEdit(str(default_value))
        step_edit = TgLineEdit("1")
        end_edit = TgLineEdit(str(default_value))
        
        # 数值验证
        param_type = type(default_value)
        if param_type is int:
            # 整型使用 QIntValidator，避免 "19.0" 之类导致 int('19.0') 抛错
            from PySide6.QtGui import QIntValidator
            int_validator = QIntValidator()
            start_edit.setValidator(int_validator)
            step_edit.setValidator(int_validator)
            end_edit.setValidator(int_validator)
        elif param_type is float:
            from PySide6.QtGui import QDoubleValidator
            dbl_validator = QDoubleValidator()
            dbl_validator.setNotation(QDoubleValidator.Notation.StandardNotation)
            start_edit.setValidator(dbl_validator)
            step_edit.setValidator(dbl_validator)
            end_edit.setValidator(dbl_validator)
        
        self.param_grid_layout.addWidget(start_edit, row, 1)
        self.param_grid_layout.addWidget(step_edit, row, 2)  
        self.param_grid_layout.addWidget(end_edit, row, 3)
        
        # 启用复选框
        from ui.components.inputs.checkbox import TgCheckBox
        enable_checkbox = TgCheckBox()
        enable_checkbox.setChecked(False)  # 默认不启用
        self.param_grid_layout.addWidget(enable_checkbox, row, 4)
        
        # 保存编辑器引用
        self.parameter_editors[param_name] = {
            'type': param_type,
            'start': start_edit,
            'step': step_edit, 
            'end': end_edit,
            'enabled': enable_checkbox
        }
    
    def _on_parallel_optimization(self):
        """多进程优化"""
        self.use_ga = False
        self._generate_setting()
    
    def _on_ga_optimization(self):
        """遗传算法优化"""
        self.use_ga = True
        self._generate_setting()
    
    def _generate_setting(self):
        """生成优化设置"""
        try:
            self.optimization_setting = OptimizationSetting()
            
            # 设置优化目标
            target_display = self.target_combo.currentText()
            target_name = self.TARGET_DISPLAY_MAP[target_display]
            self.optimization_setting.set_target(target_name)
            
            # 收集启用的参数
            enabled_params = {}
            for param_name, editors in self.parameter_editors.items():
                if not editors['enabled'].isChecked():
                    continue
                    
                param_type = editors['type']
                try:
                    # 统一解析函数：先做空值校验，再按类型转换
                    def parse_value(expected_type, text: str):
                        text = (text or "").strip()
                        if text == "":
                            raise ValueError("empty value")
                        if expected_type is int:
                            return int(text)
                        if expected_type is float:
                            return float(text)
                        return text

                    start_value = parse_value(param_type, editors['start'].text())
                    step_value = parse_value(param_type, editors['step'].text())
                    end_value = parse_value(param_type, editors['end'].text())
                    
                    if start_value == end_value:
                        # 固定值参数
                        enabled_params[param_name] = start_value
                    else:
                        # 范围参数
                        self.optimization_setting.add_parameter(
                            param_name, start_value, end_value, step_value
                        )
                        
                except ValueError as e:
                    logger.exception(e)
                    from ui.components.dialogs.message_box import TgMessageBox
                    TgMessageBox.warning(self, "参数错误", 
                                       f"参数 '{param_name}' 的值无效: {e}")
                    return
            
            if not self.optimization_setting.parameters:
                from ui.components.dialogs.message_box import TgMessageBox
                TgMessageBox.warning(self, "参数错误", "请至少启用一个参数进行优化")
                return
            
            # 遗传算法需要至少2个参数
            if self.use_ga and len(self.optimization_setting.parameters) < 2:
                from ui.components.dialogs.message_box import TgMessageBox
                TgMessageBox.warning(self, "参数错误", 
                                   f"遗传算法优化需要至少2个参数，当前只有{len(self.optimization_setting.parameters)}个参数。\n"
                                   "请启用更多参数或选择多进程优化。")
                return
            
            # 保存目标显示名称
            self.target_display_name = target_display
            
            self.accept()
            
        except Exception as e:
            logger.exception(f"Error generating optimization setting: {e}")
            from ui.components.dialogs.message_box import TgMessageBox
            TgMessageBox.warning(self, "设置错误", f"生成优化设置时发生错误: {e}")
    
    def get_setting(self):
        """获取优化设置"""
        return (self.optimization_setting.to_dict() if self.optimization_setting else None, 
                self.use_ga, 
                self.worker_spin.value(),
                getattr(self, 'target_display_name', ''))